﻿/* This Software is Licenced under MIT Licence (http://en.wikipedia.org/wiki/MIT_License)

Copyright (c) 2012 Andrea Cappelletti, Milan, Italy aka CleverWalrus)

Permission is hereby granted, free of charge, to any person obtaining a copy of this 
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge, 
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies 
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CleverBobCat.Core;

namespace CleverBobCat.EngineController
{
    public class ModuleCleverLiquidEngine : PartModule
    {
        [KSPField]
        public bool debug = false;

        [KSPField]
        public string engineGroup = "default";

        [KSPField]
        public bool engineActive = false;

        [KSPField]
        public float engineThrottle = 0F;

        // maxThrust of engine can't be == to minThrust
        public float minValue = 0.00000001F;

        private float maxThrust;
        private float minThrust;
        private float heatProduction;
        private float origMaxThrust;
        private float origMinThrust;
        private float origHeatProduction;

        // We use this for avoiding running the script unless a
        // ModuleCleverEngineController has taken control of engine
        public bool controlled = false;

        /// <summary>
        /// Constructor style setup.
        /// Per-frame update
        /// Called even if part is not active
        /// </summary>
        void Update()
        {
        }

        /// <summary>
        /// Constructor style setup.
        /// Per-physx-frame update
        /// Called even if part is not active
        /// </summary>
        void FixedUpdate()
        {
        }

        /// <summary>
        /// Constructor style setup.
        /// Called in the Part\'s Awake method. 
        /// The model may not be built by this point.
        /// </summary>
        public override void OnAwake()
        {
        }

        /// <summary>
        /// Called during the Part startup.
        /// StartState gives flag values of initial state
        /// </summary>
        public override void OnStart(StartState state)
        {
            Logger.Debug(debug, "CleverLiquidEngine.OnStart");
            LiquidFuelEngine engine = (LiquidFuelEngine)part;
            maxThrust = engine.maxThrust;
            minThrust = engine.minThrust;
            heatProduction = engine.heatProduction;
            origMaxThrust = engine.maxThrust;
            origMinThrust = engine.minThrust;
            origHeatProduction = engine.heatProduction;
            Logger.Debug(debug, "maxThrust", maxThrust.ToString());
            Logger.Debug(debug, "minThrust", minThrust.ToString());
            Logger.Debug(debug, "heatProduction", heatProduction.ToString());
            Logger.Debug(debug, "origMaxThrust", origMaxThrust.ToString());
            Logger.Debug(debug, "origMinThrust", origMinThrust.ToString());
            Logger.Debug(debug, "origHeatProduction", origHeatProduction.ToString());
        }

        /// <summary>
        /// Per-frame update
        /// Called ONLY when Part is ACTIVE!
        /// </summary>
        public override void OnUpdate()
        {
        }

        /// <summary>
        /// Per-physx-frame update
        /// Called ONLY when Part is ACTIVE!
        /// </summary>
        public override void OnFixedUpdate()
        {
            // checking controlled avoid to run the script if the vessel
            // is not the one that was activated in this scene
            if (controlled)
            {
                // We must update the FX even for non-active vessels
                // otherwise at staging the engine particle will fire
                // even if disabled by the toggle
                UpdateEngineFX();
            }
        }

        /// <summary>
        /// Called when PartModule is asked to save its values.
        /// Can save additional data here.
        /// </summary>
        /// <param name='node'>The node to save in to</param>
        public override void OnSave(ConfigNode node)
        {
        }

        /// <summary>
        /// Called when PartModule is asked to load its values.
        /// Can load additional data here.
        /// </summary>
        /// <param name='node'>The node to load from</param>
        public override void OnLoad(ConfigNode node)
        {
        }

        /// <summary>
        /// Called from ModuleCleverEngineController for changing
        /// the thrust and heat production based on the activation
        /// and slider setting this does not change the value
        /// for the engine but only the local vars.
        /// </summary>
        [KSPEvent]
        public void UpdateEngineGroup(BaseEventData data)
        {
            controlled = true;
            CleverEngineGroup engineGroupData = (CleverEngineGroup)data.Get("engineGroup");
            if (engineGroupData.name == engineGroup)
            {
                Logger.Debug(debug, "UpdateEngineGroup", "CleverLiquidEngine");
                if (engineGroupData.active)
                {
                    engineActive = true;
                    engineThrottle = engineGroupData.throttle;
                    maxThrust = minValue + origMinThrust + ((origMaxThrust - origMinThrust) * engineThrottle) / 100;
                    minThrust = origMinThrust;
                    heatProduction = (origHeatProduction * engineThrottle) / 100;
                    LogStatus();
                }
                else
                {
                    engineActive = false;
                    engineThrottle = engineGroupData.throttle;
                    maxThrust = minValue + origMinThrust;
                    minThrust = origMinThrust;
                    heatProduction = minValue;
                    LogStatus();
                }
                Logger.Debug(debug, "engineActive", engineActive.ToString());
                Logger.Debug(debug, "engineThrottle", engineThrottle.ToString());
                Logger.Debug(debug, "maxThrust", maxThrust.ToString());
                Logger.Debug(debug, "minThrust", minThrust.ToString());
                Logger.Debug(debug, "heatProduction", heatProduction.ToString());
            }

            // Update the actual engine values
            UpdateEngineThrust();
        }

        /// <summary>
        /// Called for changing the real parameters of the engine.
        /// </summary>
        private void UpdateEngineThrust()
        {
            Logger.Debug(debug, "UpdateEngineThrust", "CleverLiquidEngine");
            LiquidFuelEngine engine = (LiquidFuelEngine)part;
            engine.maxThrust = maxThrust;
            engine.minThrust = minThrust;
            engine.heatProduction = heatProduction;
            Logger.Debug(debug, "maxThrust", engine.maxThrust.ToString());
            Logger.Debug(debug, "minThrust", engine.minThrust.ToString());
            Logger.Debug(debug, "heatProduction", engine.heatProduction.ToString());
        }

        /// <summary>
        /// Called for disabling the FX when engine is disabled
        /// the "game" throttle otherwise set the FX plume
        /// </summary>
        private void UpdateEngineFX()
        {
            if (!engineActive || maxThrust <= minValue) part.findFxGroup("active").setActive(false);
        }

        private void LogStatus()
        {
            Logger.Debug(debug, "EngineGroup:[" + engineGroup + "] Active:[" + engineActive + "] Throttle:[" + engineThrottle.ToString() + "]");
        }
    }
}
